Actualmente, FORM enfrenta la necesidad y la gran oportunidad de optimizar su cadena de producción en función de la demanda de sus diversos productos. Es crucial generar predicciones precisas de la demanda para que FORM pueda aumentar la eficiencia en toda su cadena de producción, reducir costos y mejorar el servicio al cliente. Para lograr esto, se desarrollará un modelo de series temporales utilizando técnicas de modelado como SARIMA, con el fin de predecir las ventas futuras basándose en los datos históricos de ventas de los últimos años.
Se escogió un modelo SARIMA debido a que la naturaleza de los datos permite acoplarse muy bien con modelos de series de tiempo y dicho modelo logra capturar los componentes estacionales de la serie.
Se utilizó la base de datos VENTAS_FORM_FJ_2024 proporcionada por la empresa, la cual incluye un registro detallado de sus ventas en el periodo 2021-2023.
library(readr)
library(ggplot2)
library(tidyr)
library(viridis)
library(scales)
library(readxl)
library(RColorBrewer)
library(dplyr)
library(caret)
library(MASS)
library(rpart)
library(rpart.plot)
library(party)
library(gmodels)
library(knitr)
library(readxl)
library(readr)
library(dplyr)
library(cluster)
library(ggplot2)
library(corrplot)
library(tseries)
library(e1071)
library(pROC)
library(ISLR)
library(knitr)
library(gridExtra)
library(car)
library(DataExplorer)
library(tidyr)
library(ggplot2)
library(randomForest)
library(class)
library(caret)
library(cluster)
library(factoextra)
library(purrr)
library(imputeTS)
library(xts)
library(zoo)
library(tseries)
library(stats)
library(forecast)
library(astsa)
library(corrplot)
library(wordcloud)
library(tidytext)
library(AER)
library(vars)
library(dynlm)
library(mFilter)
library(TSstudio)
library(tidyverse)
library(sarima)
library(readr)
library(readxl)
library(heatmaply)
library(dplyr)
library(ggplot2)
library(psych)
library(tidyr)
library(readtext)
library(syuzhet)
library(RColorBrewer)
library(tm)
library(caret)
library(MASS)
library(rpart)
library(rpart.plot)
library(party)
library(gmodels)
library(knitr)
library(cluster)
library(e1071)
library(pROC)
library(ISLR)
library(gridExtra)
library(car)
library(DataExplorer)
library(randomForest)
library(class)
library(factoextra)
library(purrr)ventas_nv <- read_csv("/Users/gabrielmedina/Desktop/git/git/Case_Study_FORM/databases/form/VENTAS_FORM_B.csv")## Rows: 37 Columns: 6
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (1): Mes
## dbl (5): Año, Total Carton, Total Retornable, Servicios, Ventas Totales
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
head(ventas_nv)## # A tibble: 6 × 6
## Mes Año `Total Carton` `Total Retornable` Servicios `Ventas Totales`
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 Enero 2021 283978 1137 127 285242
## 2 Febrero 2021 333858 1405 0 335263
## 3 Marzo 2021 274885 5114 58 280057
## 4 Abril 2021 266280 1494 0 267774
## 5 Mayo 2021 179193 4380 4 183577
## 6 Junio 2021 140761 1980 0 142741
na_count <- colSums(is.na(ventas_nv))
na_count## Mes Año Total Carton Total Retornable
## 1 1 1 1
## Servicios Ventas Totales
## 1 1
# Renombra columnas
names(ventas_nv)[names(ventas_nv) == "Ventas Totales"] <- "Ventas_totales"
names(ventas_nv)[names(ventas_nv) == "Total Carton"] <- "Total_carton"
names(ventas_nv)[names(ventas_nv) == "Total Retornable"] <- "Total_retornable"
names(ventas_nv)## [1] "Mes" "Año" "Total_carton" "Total_retornable"
## [5] "Servicios" "Ventas_totales"
Sys.setlocale("LC_TIME", "es_ES.UTF-8")## [1] "es_ES.UTF-8"
ventas_nv <- na.omit(ventas_nv[, c("Año", "Mes", "Ventas_totales", "Total_carton", "Total_retornable", "Servicios")])
ventas_nv$Fecha <- as.Date(paste(ventas_nv$Año, ventas_nv$Mes, "01"), format = "%Y %B %d")
ventas_t <- ts(ventas_nv$Ventas_totales, start = c(as.numeric(format(min(ventas_nv$Fecha), "%Y")), as.numeric(format(min(ventas_nv$Fecha), "%m"))), frequency = 12)
ts_plot(ventas_t)Carton <- ts(ventas_nv$Total_carton, start = c(year(min(ventas_nv$Fecha)), month(min(ventas_nv$Fecha))), frequency = 12)
ts_plot(Carton)Retornable <- ts(ventas_nv$Total_retornable, start = c(year(min(ventas_nv$Fecha)), month(min(ventas_nv$Fecha))), frequency = 12)
ts_plot(Retornable)servicio <- ts(ventas_nv$Servicios, start = c(year(min(ventas_nv$Fecha)), month(min(ventas_nv$Fecha))), frequency = 12)
ts_plot(servicio)adf.test(ventas_t)##
## Augmented Dickey-Fuller Test
##
## data: ventas_t
## Dickey-Fuller = -4.7058, Lag order = 3, p-value = 0.01
## alternative hypothesis: stationary
Con la prueba de ADF podemos observar que la serie de tiempo de las ventas es estacionaria, es decir, no muestra tendencias a lo largo del tiempo y es ideal para modelar un ARIMA que logre capturar los componentes estacionales de la serie de tiempo
# Graficar la ACF y PACF
par(mfrow = c(1, 2))
acf(ventas_t, main = "ACF de Ventas Totales")
pacf(ventas_t, main = "PACF de Ventas Totales")# Ajustar el modelo ARMA con p=1 y q=1
sarima <- auto.arima(ventas_t, seasonal = TRUE)
summary(sarima)## Series: ventas_t
## ARIMA(1,0,0) with non-zero mean
##
## Coefficients:
## ar1 mean
## 0.7659 175677.34
## s.e. 0.1114 26036.11
##
## sigma^2 = 1.648e+09: log likelihood = -432.51
## AIC=871.01 AICc=871.76 BIC=875.76
##
## Training set error measures:
## ME RMSE MAE MPE MAPE MASE ACF1
## Training set -3422.67 39453.7 31583.27 -7.366077 20.37777 0.4829533 -0.1033301
El modelo ARMA(1,1) ajustado a la serie de tiempo de ventas muestra que el componente autorregresivo es altamente significativo, indicando que las ventas actuales dependen fuertemente de las ventas pasadas. Sin embargo, el componente de media móvil no es significativo. La significancia del intercepto sugiere un término constante relevante. A pesar de la variabilidad en los residuos, este modelo proporciona una base sólida para capturar las dinámicas de las ventas.
Modelo Arma
sarima_residuals<-sarima$residuals
Box.test(sarima_residuals,lag=1,type="Ljung-Box")##
## Box-Ljung test
##
## data: sarima_residuals
## X-squared = 0.41732, df = 1, p-value = 0.5183
El valor de p obtenido en la prueba de Box-Ljung (0,88) es mayor que el valor de p máximo comúnmente utilizado que es 0,05. Esto significa que no se encontró evidencia significativa de autocorrelación en los residuos, ya que el valor p es mayor que 0,05, lo que respalda la validez del modelo en términos de autocorrelación.
#Testing residuals
suppressWarnings({
sarima$residuals <- na.omit(sarima$residuals)
adf.test(sarima$residuals)
})##
## Augmented Dickey-Fuller Test
##
## data: sarima$residuals
## Dickey-Fuller = -5.1649, Lag order = 3, p-value = 0.01
## alternative hypothesis: stationary
El valor de p de 0,01, inferior al umbral de 0,05, indica una fuerte evidencia contra la hipótesis nula de no estacionariedad. Esto significa que es poco probable que los residuos sean no estacionarios.
# Realizar predicciones para los próximos 4 meses
forecast_sarima <- forecast(sarima, h = 7)
# Graficar las predicciones
autoplot(forecast_sarima) +
ggtitle("Predicciones de Ventas Totales") +
xlab("Tiempo") +
ylab("Ventas Totales")forecast_sarima## Point Forecast Lo 80 Hi 80 Lo 95 Hi 95
## Jan 2024 143252.7 91224.91 195280.5 63683.04 222822.4
## Feb 2024 150844.5 85311.21 216377.8 50619.98 251069.0
## Mar 2024 156658.8 84368.51 228949.1 46100.34 267217.2
## Apr 2024 161111.7 85137.26 237086.2 44918.81 277304.6
## May 2024 164522.1 86467.53 242576.6 45147.96 283896.2
## Jun 2024 167133.9 87884.73 246383.1 45932.74 288335.1
## Jul 2024 169134.3 89192.63 249075.9 46874.10 291394.4
El modelo SARIMA ajustado a la serie de tiempo de ventas ha sido utilizado para realizar predicciones para los próximos 12 meses. Las predicciones muestran la tendencia esperada de las ventas totales, proporcionando una herramienta valiosa para la planificación y la toma de decisiones en la optimización de la cadena de producción. La significancia del componente autorregresivo sugiere que las ventas pasadas tienen un impacto considerable en las ventas futuras, mientras que el componente de media móvil no resultó ser significativo en este modelo. Las pruebas de diagnóstico respaldan la validez del modelo, indicando que no hay autocorrelación significativa en los residuos y que los residuos son estacionarios. Se sugiere complementar el modelo con más datos históricos de la compañía, así como de variables externas que impactan a las ventas de FORM.